package cn.hunqing.web.controller;

import java.io.IOException;
import java.util.Date;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSON;

import cn.hunqing.web.dto.AccessToken;
import cn.hunqing.web.dto.UserInfo;
import cn.hunqing.web.entity.User;
import cn.hunqing.web.msg.RegisterMsgs;
import cn.hunqing.web.param.RegisterParameters;
import cn.hunqing.web.service.UserService;
import cn.hunqing.web.session.SessionUserInfo;
import cn.hunqing.web.util.SessionConstants;
import cn.hunqing.web.util.SessionUtils;
import cn.hunqing.web.util.ViewConstants;
import cn.hunqing.web.util.WeChatUtils;

/**
 * add the redirect method
 * 
 * @date 2015-07-27 21:12
 */
@Controller
@RequestMapping("/wechat")
public class LoginByWeChatController {
	private static Logger logger = LoggerFactory.getLogger(LoginByWeChatController.class);

	/**
	 * Maybe need to configure the appid in the database
	 */
	private static final String URI_ACCESSION_TOKEN_REQUEST = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
	private static final String URI_GLOBAL_ACCESSION_TOKEN_REQUEST = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
	private static final String URI_USER_INFO_REQUEST = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s";
	
//	private static final String APP_ID = "wx341e6568d7ecbb95";
//	private static final String SECRET = "546402296b51cbecb8ffd94518299301";
	private static final String WECHAT_PARAMETER_CODE = "code";

	@Autowired
	private UserService userService;
	
	/**
	 * Support the redirect value: templates, cards, index
	 * @param httpSession
	 * @param request
	 * @param response
	 * @param model
	 * @param redirect
	 * @return
	 */
	@RequestMapping("/{redirect}")
	public String callback(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response,ModelMap model,@PathVariable String redirect) {
		logger.info("Get the callback request for user center");
		logger.info("Step1, get the code from the http request from webchat");
		String codeFromWebChat = request.getParameter(WECHAT_PARAMETER_CODE);
		if (StringUtils.isEmpty(codeFromWebChat)) {
			//change to the error view in production
			model.addAttribute(RegisterParameters.RESPONSE_ERROR_MSG, RegisterMsgs.EMPTY_USERNAME);
			return ViewConstants.VIEW_ERROR;
		}
		logger.info("Step2, get the openif by the code:"+codeFromWebChat);
		AccessToken accessToken = getAccessToken(codeFromWebChat);
		if(accessToken == null || !StringUtils.isEmpty(accessToken.getErrcode())){
			logger.error("Get the accession_token error code:" +accessToken.getErrcode()+",error msg:"+accessToken.getErrmsg());
			//change to the error view in production
//			return new ModelAndView("error");
			model.addAttribute(RegisterParameters.RESPONSE_ERROR_MSG, RegisterMsgs.EMPTY_USERNAME);
			return ViewConstants.VIEW_ERROR;
		}
		logger.info("Step3, get the openif by the appid:"+WeChatUtils.APP_ID);
		AccessToken gloablAccessToken = getGlobalAccessToken();
		if(gloablAccessToken == null || !StringUtils.isEmpty(gloablAccessToken.getErrcode())){
			logger.error("Get the accession_token error code:" +gloablAccessToken.getErrcode()+",error msg:"+gloablAccessToken.getErrmsg());
			//change to the error view in production
//			return new ModelAndView("error");
			model.addAttribute(RegisterParameters.RESPONSE_ERROR_MSG, RegisterMsgs.EMPTY_USERNAME);
			return ViewConstants.VIEW_ERROR;
		}
		UserInfo userInfo = getUserInfo(gloablAccessToken.getAccess_token() , accessToken.getOpenid());
		if(userInfo == null || !StringUtils.isEmpty(userInfo.getErrcode())){
			logger.error("Get the user info error code:" +userInfo.getErrcode()+",error msg:"+userInfo.getErrmsg());
			//change to the error view in production
//			return new ModelAndView("error");
			model.addAttribute(RegisterParameters.RESPONSE_ERROR_MSG, RegisterMsgs.EMPTY_USERNAME);
			return ViewConstants.VIEW_ERROR;
		}
		
		try {
			logger.info("Step3, save or update the user info:"+userInfo.toString());
			
			SessionUserInfo	sessionUserInfo = userService.saveOrUpdate(buildUserForm(userInfo));
			
			logger.info("Step4, set user current session:"+sessionUserInfo.getId());
			
			SessionUtils.doLogin(request.getSession(), sessionUserInfo);
			
			Cookie cookie = new Cookie(SessionConstants.SESSION_USER_INFO, sessionUserInfo.getUserName());
			response.setHeader("P3P","CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"");
			response.addCookie(cookie);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "redirect:/"+redirect;
	}

	private AccessToken getAccessToken(String codeFromWebChat){
		CloseableHttpClient client = HttpClientBuilder.create().build();
		String url = String.format(URI_ACCESSION_TOKEN_REQUEST, WeChatUtils.APP_ID,WeChatUtils.APP_SECRECT,codeFromWebChat);
		CloseableHttpResponse response = null;
		try {
			response = client.execute(new HttpGet(url));
			
			String bodyAsString = EntityUtils.toString(response.getEntity(),"UTF-8"); 
			AccessToken accessToken = JSON.parseObject(bodyAsString,AccessToken.class);
			
			return accessToken;
			
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	private AccessToken getGlobalAccessToken(){
		CloseableHttpClient client = HttpClientBuilder.create().build();
		String url = String.format(URI_GLOBAL_ACCESSION_TOKEN_REQUEST, WeChatUtils.APP_ID,WeChatUtils.APP_SECRECT);
		CloseableHttpResponse response = null;
		try {
			response = client.execute(new HttpGet(url));
			
			String bodyAsString = EntityUtils.toString(response.getEntity(),"UTF-8"); 
			AccessToken accessToken = JSON.parseObject(bodyAsString,AccessToken.class);
			
			return accessToken;
			
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
	
	private UserInfo getUserInfo(String accessionToken ,String openId){
		CloseableHttpClient client = HttpClientBuilder.create().build();
		String url =  String.format(URI_USER_INFO_REQUEST, accessionToken,openId);
		CloseableHttpResponse response = null;
		try {
			logger.info("Step3, get user information by accession_token:"+accessionToken+"and openid:"+openId);
			response = client.execute(new HttpGet(url));

			String bodyAsString = EntityUtils.toString(response.getEntity(),"UTF-8"); 
			
			logger.info("Step4, get the user information body:" + bodyAsString);
			UserInfo userInfo = JSON.parseObject(bodyAsString,UserInfo.class);

			return userInfo;
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}

	private User buildUserForm(UserInfo userInfo){
		User user = new User();
		Date now = new Date();
		user.setCreateTime(now);
		user.setGender(userInfo.getSex());
		user.setHeadPicUrl(userInfo.getHeadimgurl());
		user.setIsDelete(false);
		user.setLastLoginTime(now);
		user.setOpenId(userInfo.getOpenid());
		user.setUnionId(userInfo.getUnionid());
		user.setUpdateTime(now);
		user.setUserNicName(userInfo.getNickname());
		user.setUserName("wechat_"+RandomStringUtils.random(6));
		logger.info("after buildUserForm the user opendId is" + userInfo.getOpenid());
		return user;
	}

}
